/**
 * Title: Hyperbolic engine
 * Description: jFamilyTree Engine
 * Version: provider
 * Copyright: (c) 2001-2008
 * Terms of use:see license agreement at http://treebolic.sourceforge.net/en/license.htm
 * Author: Bernard Bou
 * Company: bsys
 * Update: Mon Mar 10 00:00:00 CEST 2008
 */
package jFamilyTree.component;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

import jFamilyTree.control.Controller;
import jFamilyTree.model.INode;
import jFamilyTree.model.MenuItem;
import jFamilyTree.model.MountPoint;
import jFamilyTree.model.Settings;

/**
 * Popup context menu
 * 
 * @author Bernard Bou
 */
public class PopupMenu extends JPopupMenu
{
	private static final long serialVersionUID = 1L;

	/**
	 * Action-Image map
	 */
	static Map<Controller.Action, ImageIcon> theIconMap = makeIconMap();

	/**
	 * Make Action-Image map
	 * 
	 * @return Action-Image map
	 */
	static Map<Controller.Action, ImageIcon> makeIconMap()
	{
		Map<Controller.Action, ImageIcon> thisMap = new HashMap<Controller.Action, ImageIcon>();
		thisMap.put(Controller.Action.SEARCH, new ImageIcon(PopupMenu.class.getResource("images/find.png")));
		thisMap.put(Controller.Action.GOTO, new ImageIcon(PopupMenu.class.getResource("images/goto.png")));
		thisMap.put(Controller.Action.FOCUS, new ImageIcon(PopupMenu.class.getResource("images/focus.png")));
		return thisMap;
	}

	/**
	 * Constructor
	 */
	protected PopupMenu()
	{
	}

	/**
	 * Make popup menu
	 * 
	 * @param thisController
	 *        controller
	 * @param thisValue
	 *        input value
	 * @param thisNode
	 *        target node
	 * @param theseSettings
	 *        settings
	 * @return opoup menu
	 */
	static public JPopupMenu makePopup(final Controller thisController, String thisValue, final INode thisNode, Settings theseSettings)
	{
		final PopupMenu thisPopupMenu = new PopupMenu();

		// cancel
		JMenuItem thisCancelMenuItem = new JMenuItem("Cancel");
		thisCancelMenuItem.setIcon(new ImageIcon(PopupMenu.class.getResource("images/cancel.png")));
		thisCancelMenuItem.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
			}
		});
		thisPopupMenu.add(thisCancelMenuItem);

		// mount
		MountPoint thisMountPoint = thisNode.getMountPoint();
		if (thisMountPoint != null)
		{
			boolean isMounted = thisMountPoint instanceof MountPoint.Mounted;
			JMenuItem thisMountMenuItem = new JMenuItem(isMounted ? "UnMount" : "Mount");
			thisMountMenuItem.setIcon(new ImageIcon(PopupMenu.class.getResource("images/mount.png")));
			thisMountMenuItem.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					thisController.dispatch(Controller.Action.MOUNT, null, null, null, null, null, thisNode);
				}
			});
			thisPopupMenu.add(thisMountMenuItem);
		}

		// link
		if (thisNode.getLink() != null)
		{
			JMenuItem thisLinkMenuItem = new JMenuItem("Link");
			thisLinkMenuItem.setIcon(new ImageIcon(PopupMenu.class.getResource("images/link.png")));
			thisLinkMenuItem.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					thisController.dispatch(Controller.Action.LINK, null, null, null, null, null, thisNode);
				}
			});
			thisPopupMenu.add(thisLinkMenuItem);
		}

		// custom
		if (theseSettings.theMenu != null)
		{
			for (MenuItem thatMenuItem : theseSettings.theMenu)
			{
				try
				{
					final String thisMenuLabel = expandPercent(thatMenuItem.theLabel, thisValue, thisNode);
					final Controller.Action thisAction = thatMenuItem.theAction;
					final String thisLink = thatMenuItem.theLink;
					final String thisTarget = thatMenuItem.theTarget;
					final String thisMatchTarget = thatMenuItem.theMatchTarget;
					final Controller.MatchScope thisMatchScope = thatMenuItem.theMatchScope;
					final Controller.MatchMode thisMatchMode = thatMenuItem.theMatchMode;

					JMenuItem thisMenuItem = new JMenuItem(thisMenuLabel);
					thisMenuItem.setIcon(theIconMap.get(thisAction));
					thisMenuItem.addActionListener(new ActionListener()
					{
						public void actionPerformed(ActionEvent e)
						{
							thisController.dispatch(thisAction, thisLink, thisTarget, thisMatchTarget, thisMatchScope, thisMatchMode, thisNode);
						}
					});
					thisPopupMenu.add(thisMenuItem);
				}
				catch (ArrayIndexOutOfBoundsException e)
				{
				}
			}
		}
		return thisPopupMenu;
	}

	// S T R I N G . E X P A N D

	/**
	 * Expand string
	 * 
	 * @param thisString
	 *        string to expand
	 * @param thisValue
	 *        interactively supplied value
	 * @param thisNode
	 *        node node
	 * @return expanded string
	 */
	static public String expandPercent(String thisString, String thisValue, INode thisNode)
	{
		if (thisString == null)
			return "";

		StringBuffer thisBuffer = new StringBuffer();
		int n = thisString.length();
		for (int i = 0; i < n; i++)
		{
			char c = thisString.charAt(i);
			if (c != '%')
			{
				thisBuffer.append(c);
			}
			else
			{
				if (i < n - 1)
				{
					// c is not last : peek at next
					char c2 = thisString.charAt(++i);
					switch (c2)
					{

					// label
					case 'l':
						String thisLabel = thisNode.getLabel();
						if (thisLabel != null)
							thisBuffer.append(thisLabel.toCharArray());
						break;

					// content
					case 'c':
						String thisContent = thisNode.getContent();
						if (thisContent != null)
							thisBuffer.append(thisContent.toCharArray());
						break;

					// link url
					case 'u':
						String thisLink = thisNode.getLink();
						if (thisLink != null)
							thisBuffer.append(thisLink.toCharArray());
						break;

					// id
					case 'i':
						String thisId = thisNode.getId();
						if (thisId != null)
							thisBuffer.append(thisId.toCharArray());
						break;

					// parent
					case 'p':
						INode thisParent = thisNode.getParent();
						if (thisParent != null)
						{
							String thisParentId = thisParent.getId();
							if (thisParentId != null)
							{
								thisBuffer.append(thisParentId.toCharArray());
							}
						}
						break;

					// element value
					case 'e':
						if (thisValue != null)
							thisBuffer.append(thisValue.toCharArray());
						break;

					// escaped %
					case '%':
						thisBuffer.append(c2);
						break;

					// unrecognized
					default:
						thisBuffer.append(c);
						thisBuffer.append(c2);
					}
				}
				else
				{
					// is last : copy
					thisBuffer.append(c);
				}
			}
		}
		return thisBuffer.toString();
	}
}
